local getmetatable = getmetatable
local setmetatable = setmetatable
local module = module
local require = require
local type = type
local error = error
local pcall = pcall
local print = print
local pairs = pairs
local os = os
local tonumber = tonumber
local tostring = tostring

module('fit.ActionFixture')
_VERSION='0.2'

local Fixture = require('fit.Fixture')

-- Traversal --------------------------

local function doCells(self, cells)
    self.cells = cells
    action = self[cells:text()]
    status,err = pcall(action, self, cells)
    if not status then
        self:exception(cells, "Failed to call function " .. cells:text() ..
                "\n".. err)
    end
end

-- Actions ----------------------------

local function start(self, cells)
    local Actor = require(cells.more:text())
    self.actor = Actor()
end

local function spin(self, cells)
    wake = os.time() + tonumber(cells.more:text())
    while (os.time() < wake) do
        -- spin!
    end
end

local function enter(self, cells)
    func = self:getFunction()
    text = cells.more.more:text()
    func(self.actor, text)
end

local function press(self)
    func = self:getFunction()
    func(self.actor)
end

local function check(self, cells)
    func = self:getFunction()
    if type(self.actor.check) == "function" then
        self.actor.check(self.actor, cells.more.more, func)
    else
        self.parent.check(self.actor, cells.more.more, func)
    end
end

-- Utility ----------------------------

local function getFunctions(table)
    functions = {}
    for k,v in pairs(table) do
        if type(v) == "function" then
            functions[k] = v
        end
    end

    return functions
end

local function getFunction(self, test)
    if (test == nil) then
        test = self.cells.more:text()
    end

    result = self.actor[test]

    if result == nil or type(result) ~= "function" then
        error("No such function " .. test .. "\nFound: " .. tostring(result))
    end
    return result
end

-- Constructor ------------------------
do
    local actionFixture = Fixture()
    -- We need access to some of the parent's functions
    actionFixture.parent = {}
    actionFixture.parent.check = actionFixture.check

    function __call()
        actionFixture.start = start
        actionFixture.spin = spin
        actionFixture.enter = enter
        actionFixture.press = press
        actionFixture.check = check
        actionFixture.doCells = doCells
        actionFixture.getFunction = getFunction

        return actionFixture
    end
end

setmetatable(_M, _M)
